﻿using System;
using System.Diagnostics;
using My.Ioc;
using My.Ioc.Exceptions;

namespace HowToAvoidCyclicDependency
{
    #region Test clazz

    #region Case 1

    public class Grade
    {
        private readonly Room _room;

        public Grade(Room room)
        {
            _room = room;
        }

        public Room Room
        {
            get { return _room; }
        }
    }
    public class Room
    {
        public Grade Grade { get; set; }
    }

    #endregion

    #region Case 2

    public class Grade5
    {
        private readonly Room5 _room5;

        public Grade5(Room5 room5)
        {
            _room5 = room5;
            room5.Grade5 = this;
        }

        public Room5 Room5
        {
            get { return _room5; }
        }
    }
    public class Room5
    {
        public Grade5 Grade5 { get; set; }
    }

    #endregion

    #region Case 3

    public class Grade1
    {
        public Room1 Room1 { get; set; }
    }
    public class Room1
    {
        public Grade1 Grade1 { get; set; }
    }

    #endregion

    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            var container = new ObjectContainer(false);
            Register(container);
            Resolve(container);
            Console.ReadLine();
        }

        static void Register(IObjectContainer container)
        {
            container.Register<Grade>()
                .In(Lifetime.Transient());
            container.Register<Room>()
                .WithPropertyAutowired("Grade")
                .In(Lifetime.Transient());

            container.Register<Grade5>()
                .In(Lifetime.Transient());
            container.Register<Room5>()
                .In(Lifetime.Transient());

            container.Register<Grade1>()
                .WithPropertyAutowired("Room1")
                .In(Lifetime.Transient());
            container.Register<Room1>()
                .WithPropertyAutowired("Grade1")
                .In(Lifetime.Transient());

            container.CommitRegistrations();
        }

        static void Resolve(IObjectContainer container)
        {
            var grade1 = container.Resolve<Grade1>();
            Debug.Assert(grade1 == grade1.Room1.Grade1);

            // No cyclic dependency in constructor
            var root = container.Resolve<Room>();
            Debug.Assert(root == root.Grade.Room);

            try
            {
                // Cyclic dependency in constructor
                // The call path is: Grade => Room => Grade
                var grade = container.Resolve<Grade>();
            }
            catch (Exception ex)
            {
                Debug.Assert(ex is CyclicDependencyException);
            }

            // This should work
            var grade5 = container.Resolve<Grade5>();
            Debug.Assert(grade5 == grade5.Room5.Grade5);
        }
    }
}
